package com.shareditor.chatbotv1;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.document.Document;
//import org.apache.lucene.index.AtomicReader;
//import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.index.BinaryDocValues;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.queryparser.classic.QueryParser.Operator;
import org.apache.lucene.queryparser.flexible.standard.builders.PhraseQueryNodeBuilder;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Collector;
//import org.apache.lucene.search.FieldCache;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.LeafCollector;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Scorer;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.TopDocsCollector;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.PriorityQueue;
import org.apache.lucene.util.Version;
//import org.wltea.analyzer.lucene.IKAnalyzer;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.QueryStringDecoder;

public class Action {
	
	private static final Logger log = Logger.getLogger(Action.class);
	private static final Logger logChat = Logger.getLogger("chat");
	
	private static final int MAX_RESULT = 10;
	private static final int MAX_TOTAL_HITS = 1000000;
	private static IndexSearcher indexSearcher = null;
	private static String queries;
	static {
		IndexReader reader = null;
		try {
			//reader = DirectoryReader.open(FSDirectory.open(new File("./target/index")));
			reader = DirectoryReader.open(FSDirectory.open(Paths.get("./target/index", new String[0])));
		} catch (IOException e) {
			e.printStackTrace();
			System.exit(-1);
		}
		indexSearcher = new IndexSearcher(reader);
	}
	public static void doServlet1(FullHttpRequest req, NettyHttpServletResponse res) throws IOException, ParseException {
		ByteBuf buf = null;
		/*JSONArray result = new JSONArray();
		JSONObject item = new JSONObject();
		JSONObject ret = new JSONObject();
		item.put("question", "question");
		item.put("answer", "answer");
		item.put("score", "d.score");
		item.put("doc", "d.doc");
		item.put("expain","indexSearcher.explain(query,d.doc ).toString()");
		result.add(item);
	    ret.put("result", result);*/
	    buf = Unpooled.copiedBuffer("error".getBytes());
	    res.setContent(buf);
	}
	public static void doServlet(FullHttpRequest req, NettyHttpServletResponse res) throws IOException, ParseException {
		ByteBuf buf = null;
		QueryStringDecoder qsd = new QueryStringDecoder(req.uri());
		Map<String, List<String>> mapParameters = qsd.parameters();
		List<String> l = mapParameters.get("q");
	
		List<String> lt = mapParameters.get("t");
		
		/*if (null != l && l.size() == 1) {
			queries = l.get(0);
		}*/
		if (null != l && l.size() == 1) {
			String q = l.get(0);
			// 如果是监控程序
			System.out.println("q field problem.");
			if (q.equals("monitor")) {
				JSONObject ret = new JSONObject();
				ret.put("total", 1);
				JSONObject item = new JSONObject();
				item.put("answer", "alive");
				JSONArray result = new JSONArray();
				result.add(item);
				ret.put("result", result);
				buf = Unpooled.copiedBuffer(ret.toJSONString().getBytes());
				res.setContent(buf);
				return;
			}
			
			log.info("question=" + q);
			List<String> clientIps = mapParameters.get("clientIp");
			String clientIp = "";
			if (null != clientIps && clientIps.size() == 1) {
				clientIp = clientIps.get(0);
				log.info("clientIp=" + clientIp);
			}
			
			Query query = null;
			PriorityQueue<ScoreDoc> pq = new PriorityQueue<ScoreDoc>(MAX_RESULT) {
				
				@Override
				protected boolean lessThan(ScoreDoc a, ScoreDoc b) {
					return a.score < b.score;
				}
			};
			//MyCollector collector = new MyCollector(pq);
			
			JSONObject ret = new JSONObject();
			TopDocs topDocs ;//= collector.topDocs();
			
			//Analyzer analyzer = new IKAnalyzer(true);
			
			StandardAnalyzer analyzer = new StandardAnalyzer();
			QueryParser qp = new QueryParser("question", analyzer);
			//if (topDocs.totalHits == 0) {
				qp.setDefaultOperator(Operator.AND);
				query = qp.parse(q);
				System.out.println("lucene query=" + query.toString());
				//indexSearcher.search(query, 10);
				topDocs = indexSearcher.search(query, 10);
				//log.info("elapse " + collector.getElapse() + " " + collector.getElapse2());
				//topDocs = collector.topDocs();
			//}
			
			if (topDocs.totalHits == 0) {
				qp.setDefaultOperator(Operator.OR);
				query = qp.parse(q);
				log.info("lucene query=" + query.toString());
				//indexSearcher.search(query, collector);
				topDocs = indexSearcher.search(query, 20);
				//log.info("elapse " + collector.getElapse() + " " + collector.getElapse2());
				//topDocs = collector.topDocs();
			}
			
			
			ret.put("total", topDocs.totalHits);
			ret.put("q", q);
			System.out.println("total hits:" + topDocs.totalHits);
			JSONArray result = new JSONArray();
			String firstAnswer = "";
			for (ScoreDoc d : topDocs.scoreDocs) {
				Document doc = indexSearcher.doc(d.doc);
				String question = doc.get("question");
				String answer = doc.get("answer");
				JSONObject item = new JSONObject();
				item.put("question", question);
				if (firstAnswer.equals("")) {
					firstAnswer = answer;
				}
				item.put("answer", answer);
				item.put("score", d.score);
				item.put("doc", d.doc);
				item.put("expain",indexSearcher.explain(query,d.doc ).toString());
				result.add(item);
			}
			ret.put("result", result);
			log.info("response=" + ret);
			logChat.info(clientIp + " [" + q + "] [" + firstAnswer + "]");
			buf = Unpooled.copiedBuffer(ret.toJSONString().getBytes());
		} 
		else if (null != lt && lt.size() == 1) {
				String q = lt.get(0);
				// 如果是监控程序
				if (q.equals("monitor")) {
					JSONObject ret = new JSONObject();
					ret.put("total", 1);
					JSONObject item = new JSONObject();
					item.put("answer", "alive");
					JSONArray result = new JSONArray();
					result.add(item);
					ret.put("result", result);
					buf = Unpooled.copiedBuffer(ret.toJSONString().getBytes());
					res.setContent(buf);
					return;
				}
				
				log.info("question=" + q);
				List<String> clientIps = mapParameters.get("clientIp");
				String clientIp = "";
				if (null != clientIps && clientIps.size() == 1) {
					clientIp = clientIps.get(0);
					log.info("clientIp=" + clientIp);
				}
				
				Query query = null;
				PriorityQueue<ScoreDoc> pq = new PriorityQueue<ScoreDoc>(MAX_RESULT) {
					
					@Override
					protected boolean lessThan(ScoreDoc a, ScoreDoc b) {
						return a.score < b.score;
					}
				};
				//MyCollector collector = new MyCollector(pq);
				
				JSONObject ret = new JSONObject();
				//TopDocs topDocs = collector.topDocs();
				TopDocs topDocs;
				StandardAnalyzer analyzer = new StandardAnalyzer();
				//Analyzer analyzer = new IKAnalyzer(true);
				QueryParser qp = new QueryParser( "title", analyzer);
				//if (topDocs.totalHits == 0) {
					qp.setDefaultOperator(Operator.AND);
					query = qp.parse(q);
					log.info("lucene query=" + query.toString());
//					indexSearcher.search(query, collector);
					topDocs = indexSearcher.search(query, 20);
					//log.info("elapse " + collector.getElapse() + " " + collector.getElapse2());
//					topDocs = collector.topDocs();
				//}
				
				if (topDocs.totalHits == 0) {
					qp.setDefaultOperator(Operator.OR);
					query = qp.parse(q);
					log.info("lucene query=" + query.toString());
//					indexSearcher.search(query, collector);
					topDocs = indexSearcher.search(query, 20);
					//log.info("elapse " + collector.getElapse() + " " + collector.getElapse2());
//					topDocs = collector.topDocs();
				}
				
				
				ret.put("total", topDocs.totalHits);
				ret.put("q", q);
				JSONArray result = new JSONArray();
				String firstAnswer = "";
				for (ScoreDoc d : topDocs.scoreDocs) {
					Document doc = indexSearcher.doc(d.doc);
					String question = doc.get("title");
					String answer = doc.get("content");
					JSONObject item = new JSONObject();
					item.put("title", question);
					if (firstAnswer.equals("")) {
						firstAnswer = answer;
					}
					item.put("content", answer);
					item.put("score", d.score);
					item.put("doc", d.doc);
					result.add(item);
				}
				ret.put("result", result);
				log.info("response=" + ret);
				logChat.info(clientIp + " [" + q + "] [" + firstAnswer + "]");
				buf = Unpooled.copiedBuffer(ret.toJSONString().getBytes());
				
		}else {
		
			buf = Unpooled.copiedBuffer("error".getBytes());
		}
		res.setContent(buf);
		
		
		
		//===
        /*String usage = "Usage:\tjava com.bingo.backstage.SearchFiles [-index dir] [-field f] [-repeat n] [-queries file] [-query string] [-raw] [-paging hitsPerPage]\n\nSee http://lucene.apache.org/core/4_1_0/demo/ for details.";
        if(args.length > 0 && ("-h".equals(args[0]) || "-help".equals(args[0]))) {
            System.out.println(usage);
            System.exit(0);
        }*/
  
        /*String index = "./target/index";
        String field = "question";
        //String queries = qestion;
        int repeat = 1;
        boolean raw = false;
        String queryString = null;
        int hitsPerPage = 10;×/
  
        /*for(int reader = 0; reader < args.length; ++reader) {
            if("-index".equals(args[reader])) {
                index = args[reader + 1];
                ++reader;
            } else if("-field".equals(args[reader])) {
                field = args[reader + 1];
                ++reader;
            } else if("-queries".equals(args[reader])) {
                queries = args[reader + 1];
                ++reader;
            } else if("-query".equals(args[reader])) {
                queryString = args[reader + 1];
                ++reader;
            } else if("-repeat".equals(args[reader])) {
                repeat = Integer.parseInt(args[reader + 1]);
                ++reader;
            } else if("-raw".equals(args[reader])) {
                raw = true;
            } else if("-paging".equals(args[reader])) {
                hitsPerPage = Integer.parseInt(args[reader + 1]);
                if(hitsPerPage <= 0) {
                    System.err.println("There must be at least 1 hit per page.");
                    System.exit(1);
                }
  
                ++reader;
            }
        }*/
		//打开文件
        /*DirectoryReader var18 = DirectoryReader.open(FSDirectory.open(Paths.get(index, new String[0])));
        IndexSearcher searcher = new IndexSearcher(var18);
        StandardAnalyzer analyzer = new StandardAnalyzer();
        BufferedReader in = null;
        if(queries != null) {
            in = Files.newBufferedReader(Paths.get(queries, new String[0]), StandardCharsets.UTF_8);
        } else {
            in = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
        }
  
        QueryParser parser = new QueryParser(field, analyzer);
  
        //do {
        	queryString = queries;
            if(queries == null && queryString == null) {
                System.out.println("Enter query: ");
            }
  
            String line = queryString != null?queryString:in.readLine();
          
  
            Query query = parser.parse(line);
            System.out.println("Searching for: " + query.toString(field));
            if(repeat > 0) {
                Date start = new Date();
  
                for(int end = 0; end < repeat; ++end) {
                    searcher.search(query, 100);
                }
  
                Date var19 = new Date();
                System.out.println("Time: " + (var19.getTime() - start.getTime()) + "ms");
            }
  
            doPagingSearch(in, searcher, query, hitsPerPage, raw, queries == null && queryString == null);
        //} while(queryString == null);
  
        var18.close();*/
		//===
	}
	//=========
	
	//=========
	/*public static class MyCollector extends TopDocsCollector<ScoreDoc> {

		protected Scorer scorer;
		protected AtomicReader reader;
		protected int baseDoc;
		protected HashSet<Integer> set = new HashSet<Integer>();
		protected long elapse = 0;
		protected long elapse2 = 0;

		public long getElapse2() {
			return elapse2;
		}

		public void setElapse2(long elapse2) {
			this.elapse2 = elapse2;
		}

		public long getElapse() {
			return elapse;
		}

		public void setElapse(long elapse) {
			this.elapse = elapse;
		}

		protected MyCollector(PriorityQueue<ScoreDoc> pq) {
			super(pq);
		}

		@Override
		public void setScorer(Scorer scorer) throws IOException {
			this.scorer = scorer;
		}

		@Override
		public void collect(int doc) throws IOException {
			
			long t1 = System.currentTimeMillis();
			
			if (this.totalHits > MAX_TOTAL_HITS) {
				return;
			}
			
			String answer = this.getAnswer(doc);
			long t3 = System.currentTimeMillis();
			this.elapse2 += t3 - t1;
			if (set.contains(answer.hashCode())) {
				return;
			} else {
				set.add(answer.hashCode());
				ScoreDoc sd = new ScoreDoc(doc, this.scorer.score());
				if (this.pq.size() >= MAX_RESULT) {
					this.pq.updateTop();
					this.pq.pop();
				}
				this.pq.add(sd);
				this.totalHits++;
			}
			
			long t2 = System.currentTimeMillis();
			this.elapse += t2 - t1;
		}
		
		@Override
		public void setNextReader(AtomicReaderContext context) throws IOException {
			this.reader = context.reader();
			this.baseDoc = context.docBase;
		}

		@Override
		public boolean acceptsDocsOutOfOrder() {
			return false;
		}
		
		private String getAnswer(int doc) throws IOException {
			Document d = indexSearcher.doc(doc);
			return d.get("answer");
		}

		public LeafCollector getLeafCollector(LeafReaderContext arg0) throws IOException {
			// TODO Auto-generated method stub
			return null;
		}

		public boolean needsScores() {
			// TODO Auto-generated method stub
			return false;
		}
	}*/
	public static void doPagingSearch(BufferedReader in, IndexSearcher searcher, Query query, int hitsPerPage, boolean raw, boolean interactive) throws IOException {
        TopDocs results = searcher.search(query, 5 * hitsPerPage);
        ScoreDoc[] hits = results.scoreDocs;
        int numTotalHits = results.totalHits;
        System.out.println(numTotalHits + " total matching documents");
        int start = 0;
        int end = Math.min(numTotalHits, hitsPerPage);
  
        while(true) {
            if(end > hits.length) {
                System.out.println("Only results 1 - " + hits.length + " of " + numTotalHits + " total matching documents collected.");
                System.out.println("Collect more (y/n) ?");
                String quit = in.readLine();
                if(quit.length() == 0 || quit.charAt(0) == 110) {
                    break;
                }
  
                hits = searcher.search(query, numTotalHits).scoreDocs;
            }
  
            end = Math.min(hits.length, start + hitsPerPage);
  
            for(int var15 = start; var15 < end; ++var15) {
                if(raw) {
                    System.out.println("doc=" + hits[var15].doc + " score=" + hits[var15].score);
                } else {
                    Document line = searcher.doc(hits[var15].doc);
                    String page = line.get("path");
                    if(page != null) {
                        System.out.println(var15 + 1 + ". " + page);
                        String title = line.get("title");
                        if(title != null) {
                            System.out.println("   Title: " + line.get("title"));
                        }
                    } else {
                        System.out.println(var15 + 1 + ". No path for this document");
                    }
                }
            }
  
            if(!interactive || end == 0) {
                break;
            }
  
            if(numTotalHits >= end) {
                boolean var16 = false;
  
                while(true) {
                    System.out.print("Press ");
                    if(start - hitsPerPage >= 0) {
                        System.out.print("(p)revious page, ");
                    }
  
                    if(start + hitsPerPage < numTotalHits) {
                        System.out.print("(n)ext page, ");
                    }
  
                    System.out.println("(q)uit or enter number to jump to a page.");
                    String var17 = in.readLine();
                    if(var17.length() == 0 || var17.charAt(0) == 113) {
                        var16 = true;
                        break;
                    }
  
                    if(var17.charAt(0) == 112) {
                        start = Math.max(0, start - hitsPerPage);
                        break;
                    }
  
                    if(var17.charAt(0) == 110) {
                        if(start + hitsPerPage < numTotalHits) {
                            start += hitsPerPage;
                        }
                        break;
                    }
  
                    int var18 = Integer.parseInt(var17);
                    if((var18 - 1) * hitsPerPage < numTotalHits) {
                        start = (var18 - 1) * hitsPerPage;
                        break;
                    }
  
                    System.out.println("No such page");
                }
  
                if(var16) {
                    break;
                }
  
                end = Math.min(numTotalHits, start + hitsPerPage);
            }
        }
	}
	
	public static void doPagingSearch1(BufferedReader in, IndexSearcher searcher, Query query, int hitsPerPage, boolean raw, boolean interactive) throws IOException {
        TopDocs results = searcher.search(query, 5 * hitsPerPage);
        ScoreDoc[] hits = results.scoreDocs;
        int numTotalHits = results.totalHits;
        System.out.println(numTotalHits + " total matching documents");
        int start = 0;
        int end = Math.min(numTotalHits, hitsPerPage);
  
        while(true) {
            if(end > hits.length) {
                System.out.println("Only results 1 - " + hits.length + " of " + numTotalHits + " total matching documents collected.");
                System.out.println("Collect more (y/n) ?");
                String quit = in.readLine();
                if(quit.length() == 0 || quit.charAt(0) == 110) {
                    break;
                }
  
                hits = searcher.search(query, numTotalHits).scoreDocs;
            }
  
            end = Math.min(hits.length, start + hitsPerPage);
  
            for(int var15 = start; var15 < end; ++var15) {
                if(raw) {
                    System.out.println("doc=" + hits[var15].doc + " score=" + hits[var15].score);
                } else {
                    Document line = searcher.doc(hits[var15].doc);
                    String page = line.get("path");
                    if(page != null) {
                        System.out.println(var15 + 1 + ". " + page);
                        String title = line.get("title");
                        if(title != null) {
                            System.out.println("   Title: " + line.get("title"));
                        }
                    } else {
                        System.out.println(var15 + 1 + ". No path for this document");
                    }
                }
            }
  
            if(!interactive || end == 0) {
                break;
            }
  
            if(numTotalHits >= end) {
                boolean var16 = false;
  
                while(true) {
                    System.out.print("Press ");
                    if(start - hitsPerPage >= 0) {
                        System.out.print("(p)revious page, ");
                    }
  
                    if(start + hitsPerPage < numTotalHits) {
                        System.out.print("(n)ext page, ");
                    }
  
                    System.out.println("(q)uit or enter number to jump to a page.");
                    String var17 = in.readLine();
                    if(var17.length() == 0 || var17.charAt(0) == 113) {
                        var16 = true;
                        break;
                    }
  
                    if(var17.charAt(0) == 112) {
                        start = Math.max(0, start - hitsPerPage);
                        break;
                    }
  
                    if(var17.charAt(0) == 110) {
                        if(start + hitsPerPage < numTotalHits) {
                            start += hitsPerPage;
                        }
                        break;
                    }
  
                    int var18 = Integer.parseInt(var17);
                    if((var18 - 1) * hitsPerPage < numTotalHits) {
                        start = (var18 - 1) * hitsPerPage;
                        break;
                    }
  
                    System.out.println("No such page");
                }
  
                if(var16) {
                    break;
                }
  
                end = Math.min(numTotalHits, start + hitsPerPage);
            }
        }
	}
}
